"""
Alpha Manager 
Entidades de la base de datos
"""

import transaction
import cryptacular.bcrypt
from pyramid.security import Allow
from pyramid.security import Everyone
from pyramid.security import Authenticated
from sqlalchemy.orm import relationship
from sqlalchemy import Table
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import or_
from sqlalchemy.orm.session import make_transient
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import relation
from sqlalchemy.orm import backref
from sqlalchemy.types import DateTime
from sqlalchemy.orm import column_property
from sqlalchemy.orm import synonym
from sqlalchemy.orm import joinedload
from sqlalchemy.types import Integer
from sqlalchemy.types import Unicode
from sqlalchemy.types import Boolean
from sqlalchemy.types import LargeBinary
from sqlalchemy.types import UnicodeText
from sqlalchemy.sql import func
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension
from datetime import datetime
from datetime import date
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
DBSession2 = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
from alpha.modelos import Base


crypt = cryptacular.bcrypt.BCRYPTPasswordManager()

def hash_password(password):
    return unicode(crypt.encode(password))


"""
Tablas de la base de datos
"""

"""
Tablas de asociacion 
"""
class AsociacionRolProyecto(Base):
	__tablename__ = 'asociacion_rol_proyecto'
	left_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('proyecto.id'), primary_key=True)
	proyecto= relationship('Proyecto', backref='asociacion_rol_proyecto')


class AsociacionRolFase(Base):
	__tablename__ = 'asociacion_rol_fase'
	left_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('fase.id'), primary_key=True)
	fase = relationship('Fase', backref='asociacion_rol_fase')


class AsociacionRolTipoItem(Base):
	__tablename__ = 'asociacion_rol_tipoItem'
	left_id= Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id= Column(Integer, ForeignKey('tipoItem.id'), primary_key=True)
	tipoItem= relationship('TipoItem', backref='asociacion_rol_tipoItem')


class AsociacionUsuarioRol(Base):
	__tablename__ = 'asociacion_usuario_rol'
	left_id = Column(Integer, ForeignKey('usuario.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	rol = relationship('Rol', backref='asociacion_usuario_rol')


class AsociacionRolPermiso(Base):
	__tablename__ = 'asociacion_rol_permiso'
	left_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('permiso.id'), primary_key=True)
	tipo= Column(Unicode(50))
	permiso = relationship('Permiso', backref='asociacion_rol_permiso')


class AsociacionFaseTipoItem(Base):
	__tablename__ = 'asociacion_fase_tipo_item'
	left_id = Column(Integer, ForeignKey('fase.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('tipoItem.id'), primary_key=True)
	tipoItem = relationship('TipoItem', backref='asociacion_fase_tipo_item')


"""
Tabla Usuario: almacena los datos referentes a los usuario
"""
class Usuario(Base):
	__tablename__ = 'usuario'
	id = Column(Integer, primary_key=True)
	nombreUsuario = Column(Unicode(50), unique=True)
	_password = Column('password', Unicode(60))
	nombre = Column(Unicode(50))
	apellido = Column(Unicode(50))
	telefono = Column(Integer)
	nroDocumento = Column(Integer)
	fechaCreacion = Column(DateTime, default=datetime.now)
	mail = Column(Unicode(50))
	asociacionRol = relationship('AsociacionUsuarioRol', backref='usuario')
	liderProyecto = relationship('Proyecto', backref='usuario')
	
	def __init__(self, nombreUsuario, password, nombre, apellido, telefono, nroDocumento, mail):
		self.nombreUsuario = nombreUsuario
		self.password = password
		self.nombre = nombre
		self.apellido= apellido
		self.telefono= telefono
		self.nroDocumento= nroDocumento
		self.mail = mail
		
	def _get_password(self):
		return self._password
	
	def _set_password(self, password):
		self._password = hash_password(password)
	
	password = property(_get_password, _set_password)
	password = synonym('_password', descriptor=password)
	
	@classmethod
	def get_by_username(cls, nombreUsuario):
		return DBSession.query(cls).filter(cls.nombreUsuario == nombreUsuario).first()
	
	@classmethod
	def check_password(cls, nombreUsuario, password):
		usuario = cls.get_by_username(nombreUsuario)
		if not usuario:
			return False
		return crypt.check(usuario.password, password)
	
	def getNombreUsuario(self):
		return self.nombreUsuario
	
	def getNombre(self):
		return self.nombre
	
	def getApellido(self):
		return self.apellido
	
	def getTelefono(self):
		return self.telefono
	
	def getNroDocumento(self):
		return self.nroDocumento
	
	def getMail(self):
		return self.mail
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setNombreUsuario(self, nombreUsuario):
		self.nombreUsuario= nombreUsuario
	
	def setApellido(self, apellido):
		self.apellido= apellido
	
	def setTelefono(self, telefono):
		self.telefono= telefono
	
	def setNroDocumento(self, nroDocumento):
		self.nroDocumento= nroDocumento
	
	def setMail(self, mail):
		self.mail= mail


"""
Tabla Rol
"""
class Rol(Base):

	__tablename__ = 'rol'
	id= Column(Integer, autoincrement=True, primary_key=True)
	nombre= Column(Unicode(70), unique=True)
	descripcion= Column(Unicode(100))
	tipo= Column(Unicode(100))
	fechaCreacion= Column(DateTime, default=datetime.now)
	asociacionPermiso= relationship('AsociacionRolPermiso', backref= 'rol')
	asociacionFase= relationship('AsociacionRolFase', backref= 'rol')
	asociacionProyecto= relationship('AsociacionRolProyecto', backref= 'rol')
	asociacionTipoItem= relationship('AsociacionRolTipoItem', backref= 'rol')
	
	def __init__(self, nombreRol,descripcion):
		self.nombre = nombreRol
		self.descripcion = descripcion    
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getTipo(self):
		return self.tipo
	
	def getFecha(self):
		return self.fechaCreacion
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def setTipo(self, tipo):
		self.tipo= tipo
	
	def inicializarPermisos(self, session):
		permisos_actuales= []
		permisos_sistema= []
		for relacion in self.asociacionPermiso:
			permisos_actuales.append(relacion.permiso)
		if self.getTipo() == 'Administrador':
			permisos_sistema= session.query(Permiso).all()
		elif self.getTipo() == 'LiderProyecto':
			permisos_sistema= session.query(Permiso).filter(or_(Permiso.tipo == 'LiderProyecto', Permiso.tipo == 'LiderFase', Permiso.tipo == 'Desarrollador')).all()
		elif self.getTipo() == 'LiderFase':
			permisos_sistema= session.query(Permiso).filter(or_(Permiso.tipo == 'LiderFase', Permiso.tipo == 'Desarrollador')).all()
		elif self.getTipo() == 'Desarrollador':
			permisos_sistema= session.query(Permiso).filter(Permiso.tipo == 'Desarrollador').all()
		for permiso in permisos_sistema:
			if not (permiso in permisos_actuales):
				relacion= AsociacionRolPermiso()
				relacion.permiso= permiso
				relacion.left_id= self.id
				self.asociacionPermiso.append(relacion)
		for permiso in permisos_actuales:
			if not (permiso in permisos_sistema):
				for aso in self.asociacionPermiso:
					if aso.permiso == permiso:
						session.delete(aso)
	
	def eliminarPermisos(self, session):
		for relacion in self.asociacionPermiso:
			session.delete(relacion)




class Proyecto(Base):
	__tablename__ = 'proyecto'
	id= Column(Integer, primary_key=True)
	nombre= Column(Unicode(50), unique=True)
	descripcion= Column(Unicode(300))
	fechaCreacion = Column(DateTime, default=datetime.now)
	complejidad= Column(Integer)
	estado= Column(Unicode(20))
	fases = relationship('Fase', backref='proyecto')
	tipoItems = relationship('TipoItem', backref='proyecto')
	lider_id = Column(Integer, ForeignKey('usuario.id'))
	
	def __init__(self, nombre, descripcion):
		self.nombre= nombre
		self.descripcion= descripcion
		self.complejidad= 0
		self.estado= 'No iniciado'
		self.nroFases= 0
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getFecha(self):
		return self.fechaCreacion
	
	def getComplejidad(self):
		return self.complejidad
	
	def getEstado(self):
		return self.estado
	
	def getNroFases(self):
		return len(self.fases)
	
	def getFases(self):
		return self.fase
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setEstado(self, nuevoEstado):
		self.estado= nuevoEstado
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def reEnumerarFases(self):
		cont= 0
		for fase in self.fases:
			cont= cont + 1
			fase.setPosicionFase(cont)


class Fase(Base):
	__tablename__ = 'fase'
	id = Column(Integer, primary_key=True)
	posicionFase= Column(Integer)
	nombre= Column(Unicode(50))
	descripcion= Column(Unicode(300))
	nroItems = Column(Integer)
	nroLB = Column(Integer)
	estado = Column(Unicode(20))
	proyecto_id = Column(Integer, ForeignKey('proyecto.id'))
	asociacionTipoItem= relationship('AsociacionFaseTipoItem', backref= 'fase')
	
	def __init__(self, nombre,descripcion):
		self.nombre= nombre
		self.nroItems= 0
		self.descripcion = descripcion
		self.nroLB = 0
		self.estado = 'Inicial'
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getPosicionFase(self):
		return self.posicionFase
	
	def getNroItems(self):
		return self.nroItems
	
	def getEstado(self):
		return self.estado
	
	def getNroLB(self):
		return self.nroLB
	
	def setEstado(self, nuevoEstado):
		self.estado= nuevoEstado
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
		
	def setNroItems(self, cantidad):
		self.nroItems= cantidad
	
	def setNroLB(self, cantidad):
		self.nroLB= cantidad
	
	def setPosicionFase(self, posicionFase):
		self.posicionFase= posicionFase


class TipoItem(Base):
	__tablename__ = 'tipoItem'
	id = Column(Integer, primary_key=True)
	nombre= Column(Unicode(50))
	descripcion= Column(Unicode(50))
	atributos= relationship('Atributo', backref='tipoItem')
	proyecto_id = Column(Integer, ForeignKey('proyecto.id'))
	
	def __init__(self, nombre, descripcion):
		self.nombre= nombre
		self.descripcion= descripcion
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getNroAtributos(self):
		return len(self.atributos)
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion


class Atributo(Base):
	__tablename__ = 'atributo'
	id = Column(Integer, primary_key=True)
	nombre= Column(Unicode(50))
	tipo= Column(Unicode(50), nullable=False)
	descripcion= Column(Unicode(100))
	valorString= Column(Unicode(500))
	valorInteger= Column(Integer)
	valorFecha=  Column(DateTime)
	tipoItem_id = Column(Integer, ForeignKey('tipoItem.id'))
	
	def __init__(self, nombre, tipo):
		self.nombre= nombre
		self.tipo= tipo
	
	def getNombre(self):
		return self.nombre
	
	def getTipo(self):
		return self.tipo
	
	def getValor(self):
		if self.getTipo() == 'String':
			return self.valorString
		elif self.getTipo() == 'Integer':
			return self.valorInteger
		else:
			if self.valorFecha != None:
				return self.valorFecha.strftime("%d/%m/%y")
			else:
				return ' No existe fecha'
	
	def getDescripcion(self):
		return self.descripcion
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setValor(self, valor):
		if self.getTipo() == 'String':
			self.valorString= valor
		if self.getTipo() == 'Integer':
			self.valorInteger= valor
		if self.getTipo() == 'Fecha':
			self.valorFecha= date(valor['anho'], valor['mes'], valor['dia'])
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion


class Permiso(Base):
	__tablename__ = 'permiso'
	id= Column(Integer, autoincrement=True, primary_key=True)
	nombre = Column(Unicode(70), unique=True)
	descripcion = Column(Unicode(100))
	tipo= Column(Unicode(50))
	
	def __init__(self, nombre, tipo):
		self.nombre = nombre
		self.tipo= tipo
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getTipo(self):
		return self.tipo
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def setTipo(self, tipo):
		self.tipo= tipo


"""
Clase RootFactory para los permisos
"""
class RootFactory(object):
	__acl__ = [ (Allow, Everyone, 'view'),
				(Allow, Authenticated, 'edit') ]
	
	def __init__(self, request):
		pass
